import drawConfig from './drawConfig'
import { uuid } from '@/lib/util'
import {
    computeArea,
    isNearbyPoint,
    reverseLnglats,
    isCrossedPolygon,
    computeRegionCenterPoint,
    computePoint2LinePositionAndDistance
} from './drawUtil'

let POINT_ICON = null // 白色点标记

// 用于处理圈画逻辑
export default class Draw {
    constructor (map, func, isMulti = true, addPointCheckFunc = null) {
        this.map = map
        this.polylineArr = [] // 线条对象
        this.pointsArr = [] // 点集
        this.markersArr = [] // 点标记集合
        this.addStack = [] // 添加栈 { uuid index }
        this.drawGroup = null // 绘制图形、标记放置的图层
        this.area = 0 // 面积
        this.isStarted = false
        this.isClosed = false
        this.canUndo = false
        this.canClear = false
        this.isFinished = false
        this.syncStatusFun = func // 同步 area、isStarted、isClosed状态
        this.isMulti = isMulti // 可以绘制多个多边形
        this.addPointCheckFunc = addPointCheckFunc // 添加点的时候，先校验点能否添加
        this.ext = null
        this.dragEndTimestamp = 0
        map.on('click', e => {
            // console.log('map click....', this.isStarted, this.isFinished)
            if (this.isStarted && !this.isFinished) {
                this.doMapClick(e.latlng)
            }
        })
    }

    init (datas = null, isStarted = true, ext = null) {
        const that = this
        if (that.drawGroup) {
            that.drawGroup.clearLayers()
        } else {
            that.drawGroup = L.layerGroup().addTo(that.map)
        }
        that.map._drawGroup = that.drawGroup
        if (datas) {
            that.pointsArr = datas.map(item => {
                return {
                    id: item.boundId,
                    points: item.boundary.map(p => { return { id: uuid(), latlng: p } })
                }
            })
            that.polylineArr = []
            that.pointsArr.forEach((item, index) => {
                item.points.forEach(p => {
                    that.addMarker(p.id, p.latlng, index)
                })
            })
            that.computeArea()
            that.isStarted = true
            that.isClosed = true
        } else {
            that.polylineArr = []
            that.pointsArr = []
            that.markersArr = []
            that.addStack = []
            that.area = 0
            that.isStarted = isStarted
            that.isClosed = false
        }
        if (ext) {
            that.ext = ext
        }
        that.syncStatus()
    }

    // 点击地图事件
    doMapClick ({ lat, lng }) {
        const that = this
        const pointsArr = that.pointsArr
        const latlng = [lat, lng]
        if (Date.now() - that.dragEndTimestamp < 800) {
            return false
        }
        if (that.isClosed) {
            if (!that.insertPoint(latlng) && that.isMulti) {
                pointsArr.push({ id: uuid(), points: [] })
                that.isClosed = false
                that.syncStatus()
            } else {
                return false
            }
        }

        if (that.isMulti || (that.addPointCheckFunc && that.addPointCheckFunc(latlng, pointsArr))) {
            const map = that.map
            const len = pointsArr.length
            if (len && pointsArr[len - 1].points.length > 2) {
                // 判定与第一个点的距离，如果非常接近，则闭合绘制的地块, TODO 计算两点间距离
                const points = pointsArr[len - 1].points
                if (isNearbyPoint(map, latlng, points[0].latlng)) {
                    that.isClosed = true // 绘制完成
                    const [lat, lng] = points[0].latlng
                    that.drawCircleMarker([lat, lng])
                    that.computeArea()
                    that.syncStatus()
                } else {
                    that.drawCircleMarker(latlng)
                }
            } else {
                that.drawCircleMarker(latlng)
            }
        }
    }

    // 与现有线段位置近的话，插入点，成功返回true
    insertPoint (latlng) {
        const that = this
        const pointsArr = that.pointsArr
        if (pointsArr.length == 0) {
            return false
        }
        const map = that.map
        let p1 = null
        let p2 = null
        const currPoint = map.latLngToLayerPoint(latlng)
        let distance = 0
        let currMinDistance = 1000
        let disResArr = null
        let resPointIndex = -1
        let resPolygonIndex = -1
        let points = null

        for (let j = 0; j < pointsArr.length; j++) {
            points = pointsArr[j].points
            for (let i = 0; i < points.length - 1; i++) {
                p1 = map.latLngToLayerPoint(L.latLng(points[i].latlng))
                p2 = map.latLngToLayerPoint(L.latLng(points[i + 1].latlng))
                disResArr = computePoint2LinePositionAndDistance([currPoint.x, currPoint.y], [p1.x, p1.y], [p2.x, p2.y])
                distance = disResArr[0]
                if (distance < currMinDistance) {
                    currMinDistance = distance
                    resPointIndex = i
                    resPolygonIndex = j
                }
            }
        }
        if (currMinDistance < drawConfig.minInsertDistance) { // 可以插入
            const id = uuid()
            // 挪动后面的点
            points = pointsArr[resPolygonIndex].points
            for (let j = points.length - 1; j > resPointIndex; j--) {
                points[j + 1] = points[j]
            }
            points[resPointIndex + 1] = { id, latlng }
            that.addMarker(id, latlng, resPolygonIndex) // 添加白点标记
            that.computeArea()
            that.syncStatus()
            return true
        } else {
            that.syncStatus()
            return false
        }
    }

    // 添加白点标记
    addMarker (id, latlng, index) {
        const that = this
        that.addStack.push({ id, index })
        if (!POINT_ICON) {
            POINT_ICON = L.icon(drawConfig.iconOption)
        }
        const marker = L.marker(latlng, { icon: POINT_ICON, draggable: true }).addTo(that.drawGroup)
        marker.uid = id
        marker.uindex = index
        marker.on('drag', e => { that.doDragCircleMarker(e) })
        const markersArr = that.markersArr
        if (!markersArr[index]) {
            markersArr[index] = []
        }
        markersArr[index].push(marker)
        that.refreshPolyline(index)
        that.syncStatus()
    }

    // 绘制白点标记
    drawCircleMarker (latlng) {
        const that = this
        const pointsArr = that.pointsArr
        if (pointsArr.length == 0) {
            pointsArr.push({ id: uuid(), points: [] })
        }
        const index = pointsArr.length - 1
        const points = pointsArr[index].points
        const id = uuid()
        points.push({ id, latlng })
        that.addMarker(id, latlng, index)
    }

    // 刷新绘制线条
    refreshPolyline (index) {
        const that = this
        if (!that.polylineArr[index]) {
            that.polylineArr[index] = L.polyline(that.pointsArr[index].points.map(p => p.latlng), drawConfig.groundStyle.focused).addTo(that.drawGroup)
        } else {
            const pointObj = that.pointsArr[index]
            if (pointObj) {
                that.polylineArr[index].setLatLngs(pointObj.points.map(p => p.latlng))
            } else {
                that.polylineArr[index].removeFrom(that.drawGroup)
                that.polylineArr.splice(index, 1)
            }
        }
        that.refreshPolylineLabels()
    }

    // 拖动标记白点的处理
    doDragCircleMarker (e) {
        const that = this
        if (that.isFinished) {
            return
        }
        const marker = e.target
        const uid = marker.uid
        const index = marker.uindex
        const points = that.pointsArr[index].points
        const pointIndex = points.findIndex(p => p.id == uid)
        if (pointIndex >= 0) {
            const point = points[pointIndex]
            const { lat, lng } = e.latlng
            point.latlng = [lat, lng]
            const len = points.length
            if ((index < that.pointsArr.length - 1 || that.isClosed) && (pointIndex == 0 || pointIndex == len - 1)) {
                const markers = that.markersArr[index]
                let marker = null
                if (pointIndex == 0) {
                    points[len - 1].latlng = [lat, lng]
                    marker = markers.find(m => m.uid == points[len - 1].id)
                } else if (pointIndex == len - 1) {
                    points[0].latlng = [lat, lng]
                    marker = markers.find(m => m.uid == points[0].id)
                }
                if (marker) {
                    marker.setLatLng(e.latlng)
                }
            }
            that.dragEndTimestamp = Date.now()
            that.computeArea()
            that.refreshPolyline(index)
            that.syncStatus()
        }
    }

    // 撤销上一步
    doUndo () {
        const that = this
        const addStack = that.addStack
        if (addStack.length) {
            const { id: pointId, index: polygonIndex } = addStack.pop()
            const points = that.pointsArr[polygonIndex].points
            const pointIndex = points.findIndex(p => p.id == pointId)
            if (pointIndex >= 0) {
                points.splice(pointIndex, 1)
                if (points.length) {
                    that.isClosed = false
                } else {
                    that.pointsArr.splice(polygonIndex, 1)
                    that.isClosed = !!that.pointsArr.length
                }
                that.syncStatus()
            }
            const markers = that.markersArr[polygonIndex]
            const markerIndex = markers.findIndex(m => m.uid == pointId)
            if (markerIndex >= 0) {
                const marker = markers[markerIndex]
                markers.splice(markerIndex, 1)
                marker.removeFrom(that.drawGroup)
                if (!markers.length) {
                    that.markersArr.splice(polygonIndex, 1)
                }
            }
            that.refreshPolyline(polygonIndex)
        }
    }

    // 校验绘制是否符合
    doCheck () {
        const that = this
        const pointsArr = that.pointsArr
        if (pointsArr.length == 0) {
            // return { status: false, msg: '请您绘制范围！' }
            return
        }
        if (!that.isClosed) {
            return { status: false, msg: '请您绘制完成！' }
        }
        let points = null
        let otherPoints = null
        let p1Arr = null
        let p2Arr = null
        // =====================================判断是否有交叉
        for (let i = 0; i < pointsArr.length; i++) {
            points = pointsArr[i].points.map(item => item.latlng)
            if (isCrossedPolygon(that.map, points)) {
                return { status: false, msg: '绘制的区域不能有交叉，请您修改！' }
            }
            p1Arr = turf.polygon([reverseLnglats(points)])
            for (let j = i + 1; j < pointsArr.length; j++) {
                otherPoints = pointsArr[j].points.map(item => item.latlng)
                p2Arr = turf.polygon([reverseLnglats(otherPoints)])
                if (turf.booleanWithin(p1Arr, p2Arr) || turf.booleanWithin(p2Arr, p1Arr) || turf.booleanOverlap(p1Arr, p2Arr)) {
                    return { status: false, msg: '绘制区域重叠，请您修改！' }
                }
            }
        }
        return { status: true }
    }

    // 计算面积
    computeArea () {
        const that = this
        const pointsArr = that.pointsArr
        let area = 0
        let len = pointsArr.length
        if (!that.isClosed) {
            len = len - 1
        }
        let arr = null
        for (let i = 0; i < len; i++) {
            arr = pointsArr[i].points.map(item => item.latlng)
            area += computeArea(arr)
        }
        that.area = area ? area.toFixed(2) : ''
    }

    // 获取圈画数据，路径点的坐标
    getDrawDatas () {
        const that = this
        const datas = []
        const pointsArr = that.pointsArr
        let latlngs = null
        let area = 0
        let center = null
        let totalArea = 0
        let zoneCenter = null
        pointsArr.forEach(polygon => {
            latlngs = polygon.points.map(p => p.latlng)
            area = computeArea(latlngs)
            totalArea += area
            zoneCenter = computeRegionCenterPoint(latlngs)
            datas.push({ boundary: latlngs, center: zoneCenter, area, boundId: isNaN(polygon.id) ? '' : polygon.id })
            if (!center) {
                center = zoneCenter
            }
        })
        totalArea = totalArea.toFixed(2) - 0
        if (that.ext) {
            return { center, datas, totalArea, ...that.ext }
        } else {
            return { center, datas, totalArea }
        }
    }

    // 同步状态值
    syncStatus () {
        const that = this
        if (that.syncStatusFun) {
            that.syncStatusFun({
                area: that.area,
                isStarted: that.isStarted,
                isClosed: that.isClosed,
                canUndo: that.addStack.length > 0,
                canClear: !!(that.isStarted && that.pointsArr.length),
                pointsArr: that.pointsArr
            })
        }
    }

    // 删除范围
    delBound (index) {
        const that = this
        const drawGroup = that.drawGroup
        const isLast = index == that.pointsArr.length - 1
        that.addStack = that.addStack.filter(item => item.index != index)
        that.addStack.forEach(ope => {
            if (ope.index > index) { ope.index = ope.index - 1 }
        })
        that.markersArr[index].forEach(marker => marker.removeFrom(drawGroup))
        that.markersArr.splice(index, 1)
        that.markersArr.forEach((arr, arrIndex) => {
            arr.forEach(marker => { marker.nIndex = arrIndex })
        })
        that.polylineArr[index].unbindTooltip()
        that.polylineArr[index].removeFrom(drawGroup)
        that.polylineArr.splice(index, 1)
        that.pointsArr.splice(index, 1)
        if (isLast && !that.isClosed) {
            that.isClosed = true
        }
        that.computeArea()
        that.refreshPolylineLabels()
        that.syncStatus()
    }

    // 刷新地块上的标签
    refreshPolylineLabels () {
        const that = this
        const pointsArr = that.pointsArr
        let label = null
        let points = null

        that.drawGroup.eachLayer(layer => {
            if (layer.boundlabel) {
                layer.removeFrom(that.drawGroup)
            }
        })
        if (that.polylineArr.length > 1) {
            that.polylineArr.forEach((line, index) => {
                points = pointsArr[index].points.map(item => item.latlng)
                if (points.length > 3) {
                    label = L.circleMarker(computeRegionCenterPoint(points), { radius: 0, opacity: 0, interactive: false }).addTo(that.drawGroup)
                    label.boundlabel = true
                    label.bindTooltip('范围' + (index + 1), { direction: 'center', permanent: true, className: 'bound-label' })
                }
            })
        }
    }

    // 设置this.isFinished状态值
    setFinishedStatus (tag) {
        this.isFinished = tag
        this.markersArr.forEach(arr => {
            arr.forEach(m => {
                // console.log('m====', m)
                if (m.dragging) {
                    tag ? m.dragging.disable() : m.dragging.enable()
                }
            })
        })
    }
}
